package cn.jingyuan.bee.system;

import cn.jingyuan.bee.utils.StringUtils;
import cn.jingyuan.bee.utils.convert.Convert;
import cn.jingyuan.bee.utils.lang.Console;
import cn.jingyuan.bee.utils.lang.Singleton;

import java.io.PrintWriter;
import java.lang.management.*;
import java.util.List;
import java.util.Properties;

/**
 * Java 的 System 类封装工具类。<br>
 * 参考：http://blog.csdn.net/zhongweijian/article/details/7619383
 */
public class SystemUtils {

    // ----- Java 运行时环境信息 ----- //

    /**
     * Java 运行时环境规范名称的 KEY
     */
    public final static String SPECIFICATION_NAME = SystemPropsKeys.SPECIFICATION_NAME;

    /**
     * Java 运行时环境版本的 KEY
     */
    public final static String VERSION = SystemPropsKeys.VERSION;

    /**
     * Java 运行时环境规范版本的 KEY
     */
    public final static String SPECIFICATION_VERSION = SystemPropsKeys.SPECIFICATION_VERSION;

    /**
     * Java 运行时环境供应商的 KEY
     */
    public final static String VENDOR = SystemPropsKeys.VENDOR;

    /**
     * Java 运行时环境规范供应商的 KEY
     */
    public final static String SPECIFICATION_VENDOR = SystemPropsKeys.SPECIFICATION_VENDOR;

    /**
     * Java 供应商的 URL 的 KEY
     */
    public final static String VENDOR_URL = SystemPropsKeys.VENDOR_URL;

    /**
     * Java 安装目录的 KEY
     */
    public final static String HOME = SystemPropsKeys.HOME;

    /**
     * 加载库时搜索的路径列表的 KEY
     */
    public final static String LIBRARY_PATH = SystemPropsKeys.LIBRARY_PATH;

    /**
     * 默认的临时文件路径的 KEY
     */
    public final static String TMPDIR = SystemPropsKeys.TMPDIR;

    /**
     * 要使用的 JIT 编译器的名称的 KEY
     */
    public final static String COMPILER = SystemPropsKeys.COMPILER;

    /**
     * 一个或多个扩展目录的路径的 KEY
     */
    public final static String EXT_DIRS = SystemPropsKeys.EXT_DIRS;

    // ----- Java 虚拟机信息 -----//

    /**
     * Java 虚拟机实现名称的 KEY
     */
    public final static String VM_NAME = SystemPropsKeys.VM_NAME;

    /**
     * Java 虚拟机规范名称的 KEY
     */
    public final static String VM_SPECIFICATION_NAME = SystemPropsKeys.VM_SPECIFICATION_NAME;

    /**
     * Java 虚拟机实现版本的 KEY
     */
    public final static String VM_VERSION = SystemPropsKeys.VM_VERSION;

    /**
     * Java 虚拟机规范版本的 KEY
     */
    public final static String VM_SPECIFICATION_VERSION = SystemPropsKeys.VM_SPECIFICATION_VERSION;

    /**
     * Java 虚拟机实现供应商的 KEY
     */
    public final static String VM_VENDOR = SystemPropsKeys.VM_VENDOR;

    /**
     * Java 虚拟机规范供应商的 KEY
     */
    public final static String VM_SPECIFICATION_VENDOR = SystemPropsKeys.VM_SPECIFICATION_VENDOR;

    // ----- Java 类信息 -----//

    /**
     * Java 类格式版本号的 KEY
     */
    public final static String CLASS_VERSION = SystemPropsKeys.CLASS_VERSION;

    /**
     * Java 类路径的 KEY
     */
    public final static String CLASS_PATH = SystemPropsKeys.CLASS_PATH;

    // ----- OS 信息 -----//

    /**
     * 操作系统的名称的 KEY
     */
    public final static String OS_NAME = SystemPropsKeys.OS_NAME;

    /**
     * 操作系统的架构的 KEY
     */
    public final static String OS_ARCH = SystemPropsKeys.OS_ARCH;

    /**
     * 操作系统的版本的 KEY
     */
    public final static String OS_VERSION = SystemPropsKeys.OS_VERSION;

    /**
     * 文件分隔符（在 UNIX 系统中是“/”）的 KEY
     */
    public final static String FILE_SEPARATOR = SystemPropsKeys.FILE_SEPARATOR;

    /**
     * 路径分隔符（在 UNIX 系统中是“:”）的 KEY
     */
    public final static String PATH_SEPARATOR = SystemPropsKeys.PATH_SEPARATOR;

    /**
     * 行分隔符（在 UNIX 系统中是“\n”）的 KEY
     */
    public final static String LINE_SEPARATOR = SystemPropsKeys.LINE_SEPARATOR;

    // ----- 用户信息 -----//

    /**
     * 用户的账户名称的 KEY
     */
    public final static String USER_NAME = SystemPropsKeys.USER_NAME;

    /**
     * 用户的主目录的 KEY
     */
    public final static String USER_HOME = SystemPropsKeys.USER_HOME;

    /**
     * 用户的当前工作目录的 KEY
     */
    public final static String USER_DIR = SystemPropsKeys.USER_DIR;

    // ----------------------------------------------------------------------- Basic start

    /**
     * 取得系统属性，如果因为 Java 安全的限制而失败，则将错误打在 Log 中，然后返回 defaultValue
     *
     * @param name 属性名
     * @param defaultValue 默认值
     *
     * @return 属性值或defaultValue
     *
     * @see System#getProperty(String)
     * @see System#getenv(String)
     */
    public static String get(String name, String defaultValue) {
        return StringUtils.nullToDefault(get(name, false), defaultValue);
    }

    /**
     * 取得系统属性，如果因为 Java 安全的限制而失败，则将错误打在 Log 中，然后返回 {@code null}
     *
     * @param name 属性名
     * @param quiet 安静模式，不将出错信息打在<code>System.err</code>中
     *
     * @return 属性值或{@code null}
     *
     * @see System#getProperty(String)
     * @see System#getenv(String)
     */
    public static String get(String name, boolean quiet) {
        String value = null;
        try {
            value = System.getProperty(name);
        } catch (SecurityException e) {
            if (false == quiet) {
                Console.error("Caught a SecurityException reading the system property '{}'; " +
                        "the SystemUtil property value will default to null.", name);
            }
        }

        if (null == value) {
            try {
                value = System.getenv(name);
            } catch (SecurityException e) {
                if (false == quiet) {
                    Console.error("Caught a SecurityException reading the system env '{}'; " +
                            "the SystemUtil env value will default to null.", name);
                }
            }
        }

        return value;
    }

    /**
     * 获得 System 属性
     *
     * @param key 键
     *
     * @return 属性值
     *
     * @see System#getProperty(String)
     * @see System#getenv(String)
     */
    public static String get(String key) {
        return get(key, null);
    }

    /**
     * 获得 boolean 类型值
     *
     * @param key 键
     * @param defaultValue 默认值
     *
     * @return 值
     */
    public static boolean getBoolean(String key, boolean defaultValue) {
        String value = get(key);
        if (value == null) {
            return defaultValue;
        }

        value = value.trim().toLowerCase();
        if (value.isEmpty()) {
            return true;
        }

        return Convert.toBool(value, defaultValue);
    }

    /**
     * 获得 int 类型值
     *
     * @param key 键
     * @param defaultValue 默认值
     *
     * @return 值
     */
    public static long getInt(String key, int defaultValue) {
        return Convert.toInt(get(key), defaultValue);
    }

    /**
     * 获得 long 类型值
     *
     * @param key 键
     * @param defaultValue 默认值
     *
     * @return 值
     */
    public static long getLong(String key, long defaultValue) {
        return Convert.toLong(get(key), defaultValue);
    }

    /**
     * @return 属性列表
     */
    public static Properties props() {
        return System.getProperties();
    }

    /**
     * 获取当前进程 PID
     *
     * @return 当前进程 ID
     */
    public static long getCurrentPID() {
        return Long.parseLong(getRuntimeMXBean().getName().split("@")[0]);
    }
    // ----------------------------------------------------------------------- Basic end

    /**
     * 返回 Java 虚拟机类加载系统相关属性
     *
     * @return {@link ClassLoadingMXBean}
     */
    public static ClassLoadingMXBean getClassLoadingMXBean() {
        return ManagementFactory.getClassLoadingMXBean();
    }

    /**
     * 返回 Java 虚拟机内存系统相关属性
     *
     * @return {@link MemoryMXBean}
     */
    public static MemoryMXBean getMemoryMXBean() {
        return ManagementFactory.getMemoryMXBean();
    }

    /**
     * 返回 Java 虚拟机线程系统相关属性
     *
     * @return {@link ThreadMXBean}
     */
    public static ThreadMXBean getThreadMXBean() {
        return ManagementFactory.getThreadMXBean();
    }

    /**
     * 返回 Java 虚拟机运行时系统相关属性
     *
     * @return {@link RuntimeMXBean}
     */
    public static RuntimeMXBean getRuntimeMXBean() {
        return ManagementFactory.getRuntimeMXBean();
    }

    /**
     * 返回 Java 虚拟机编译系统相关属性<br>
     * 如果没有编译系统，则返回<code>null</code>
     *
     * @return a {@link CompilationMXBean} ，如果没有编译系统，则返回<code>null</code>
     */
    public static CompilationMXBean getCompilationMXBean() {
        return ManagementFactory.getCompilationMXBean();
    }

    /**
     * 返回 Java 虚拟机运行下的操作系统相关信息属性
     *
     * @return {@link OperatingSystemMXBean}
     */
    public static OperatingSystemMXBean getOperatingSystemMXBean() {
        return ManagementFactory.getOperatingSystemMXBean();
    }

    /**
     * 获取 Java 虚拟机中的{@link MemoryPoolMXBean} 列表<br>
     * The Java virtual machine can have one or more memory pools. It may add or remove memory pools during execution.
     *
     * @return a list of <tt>MemoryPoolMXBean</tt> objects.
     */
    public static List<MemoryPoolMXBean> getMemoryPoolMXBeans() {
        return ManagementFactory.getMemoryPoolMXBeans();
    }

    /**
     * 获取 Java 虚拟机中的{@link MemoryManagerMXBean} 列表<br>
     * The Java virtual machine can have one or more memory managers. It may add or remove memory managers during execution.
     *
     * @return a list of <tt>MemoryManagerMXBean</tt> objects.
     */
    public static List<MemoryManagerMXBean> getMemoryManagerMXBeans() {
        return ManagementFactory.getMemoryManagerMXBeans();
    }

    /**
     * 获取 Java 虚拟机中的{@link GarbageCollectorMXBean} 列表
     *
     * @return {@link GarbageCollectorMXBean} 列表
     */
    public static List<GarbageCollectorMXBean> getGarbageCollectorMXBeans() {
        return ManagementFactory.getGarbageCollectorMXBeans();
    }

    /**
     * 取得Java Virtual Machine Specification 的信息。
     *
     * @return <code>JvmSpecInfo</code>对象
     */
    public static JvmSpecInfo getJvmSpecInfo() {
        return Singleton.get(JvmSpecInfo.class);
    }

    /**
     * 取得Java Virtual Machine Implementation 的信息。
     *
     * @return <code>JvmInfo</code>对象
     */
    public static JvmInfo getJvmInfo() {
        return Singleton.get(JvmInfo.class);
    }

    /**
     * 取得Java Specification 的信息。
     *
     * @return <code>JavaSpecInfo</code>对象
     */
    public static JavaSpecInfo getJavaSpecInfo() {
        return Singleton.get(JavaSpecInfo.class);
    }

    /**
     * 取得Java Implementation 的信息。
     *
     * @return <code>JavaInfo</code>对象
     */
    public static JavaInfo getJavaInfo() {
        return Singleton.get(JavaInfo.class);
    }

    /**
     * 取得当前运行的 JRE 的信息。
     *
     * @return <code>JreInfo</code>对象
     */
    public static JavaRuntimeInfo getJavaRuntimeInfo() {
        return Singleton.get(JavaRuntimeInfo.class);
    }

    /**
     * 取得 OS 的信息。
     *
     * @return <code>OsInfo</code>对象
     */
    public static OsInfo getOsInfo() {
        return Singleton.get(OsInfo.class);
    }

    /**
     * 取得 User 的信息。
     *
     * @return <code>UserInfo</code>对象
     */
    public static UserInfo getUserInfo() {
        return Singleton.get(UserInfo.class);
    }

    /**
     * 取得 Host 的信息。
     *
     * @return <code>HostInfo</code>对象
     */
    public static HostInfo getHostInfo() {
        return Singleton.get(HostInfo.class);
    }

    /**
     * 取得 Runtime 的信息。
     *
     * @return <code>RuntimeInfo</code>对象
     */
    public static RuntimeInfo getRuntimeInfo() {
        return Singleton.get(RuntimeInfo.class);
    }

    /**
     * 获取 JVM 中内存总大小
     *
     * @return 内存总大小
     */
    public static long getTotalMemory() {
        return Runtime.getRuntime().totalMemory();
    }

    /**
     * 获取 JVM 中内存剩余大小
     *
     * @return 内存剩余大小
     */
    public static long getFreeMemory() {
        return Runtime.getRuntime().freeMemory();
    }

    /**
     * 获取 JVM 可用的内存总大小
     *
     * @return JVM 可用的内存总大小
     */
    public static long getMaxMemory() {
        return Runtime.getRuntime().maxMemory();
    }

    /**
     * 获取总线程数
     *
     * @return 总线程数
     */
    public static int getTotalThreadCount() {
        ThreadGroup parentThread = Thread.currentThread().getThreadGroup();
        while (null != parentThread.getParent()) {
            parentThread = parentThread.getParent();
        }
        return parentThread.activeCount();
    }

    // ------------------------------------------------------------------ Dump

    /**
     * 将系统信息输出到<code>System.out</code>中。
     */
    public static void dumpSystemInfo() {
        dumpSystemInfo(new PrintWriter(System.out));
    }

    /**
     * 将系统信息输出到指定<code>PrintWriter</code>中。
     *
     * @param out <code>PrintWriter</code>输出流
     */
    public static void dumpSystemInfo(PrintWriter out) {
        out.println("--------------");
        out.println(getJvmSpecInfo());
        out.println("--------------");
        out.println(getJvmInfo());
        out.println("--------------");
        out.println(getJavaSpecInfo());
        out.println("--------------");
        out.println(getJavaInfo());
        out.println("--------------");
        out.println(getJavaRuntimeInfo());
        out.println("--------------");
        out.println(getOsInfo());
        out.println("--------------");
        out.println(getUserInfo());
        out.println("--------------");
        out.println(getHostInfo());
        out.println("--------------");
        out.println(getRuntimeInfo());
        out.println("--------------");
        out.flush();
    }

    /**
     * 输出到<code>StringBuilder</code>。
     *
     * @param builder <code>StringBuilder</code>对象
     * @param caption 标题
     * @param value 值
     */
    protected static void append(StringBuilder builder, String caption, Object value) {
        builder.append(caption).append(StringUtils.nullToDefault(Convert.toString(value), "[n/a]")).append("\n");
    }

}
